package com.xiweicheng.test.proxy;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import com.xiweicheng.test.proxy.resp.handler.IRespHandler;
import com.xiweicheng.test.proxy.resp.handler.RespHandlerFactory;

import lombok.extern.log4j.Log4j;

/* 
 * 利用HttpClient进行post请求的工具类
 * http://blog.csdn.net/guozili1/article/details/53995121
 * http://www.cnblogs.com/wangkang0320/p/6874795.html 
 */
@Log4j
public class ProxyUtil {

	public static RespDTO request(Map<String, String> headers, String requestUrl, String requestMethod,
			String outputStr) {

		if (requestUrl.startsWith("https://")) {
			return ProxyUtil.httpsRequest(headers, requestUrl, requestMethod, outputStr);
		}

		return ProxyUtil.httpRequest(headers, requestUrl, requestMethod, outputStr);
	}

	// 处理http请求 requestUrl为请求地址 requestMethod请求方式，值为"GET"或"POST"
	public static RespDTO httpRequest(Map<String, String> headers, String requestUrl, String requestMethod,
			String outputStr) {

		try {

			URL url = new URL(requestUrl);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();

			Utils.setReqHeader(headers, conn);

			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setRequestMethod(requestMethod);
			conn.connect();

			// 往服务器端写内容 也就是发起http请求需要带的参数
			if (null != outputStr) {
				OutputStream os = conn.getOutputStream();
				os.write(outputStr.getBytes("utf-8"));
				os.close();
			}

			// 读取服务器端返回的内容
			InputStream is = conn.getInputStream();

			String content = IOUtils.toString(is, "UTF-8");
			IOUtils.closeQuietly(is);
			conn.disconnect();
			return RespDTO.builder().content(content).headers(conn.getHeaderFields()).code(conn.getResponseCode())
					.cookie(conn.getHeaderField(Constants.HEADER_SET_COOKIE)).build();

		} catch (Exception e) {
			e.printStackTrace();
			log.error("http request error:{}", e);
		}

		return RespDTO.builder().build();
	}

	/**
	 * 发起https请求并获取结果
	 * 
	 * @param requestUrl
	 *            请求地址
	 * @param requestMethod
	 *            请求方式（GET、POST）
	 * @param outputStr
	 *            提交的数据
	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
	 */
	public static RespDTO httpsRequest(Map<String, String> headers, String requestUrl, String requestMethod,
			String outputStr) {

		try {
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化
			TrustManager[] tm = { new MyX509TrustManager() };
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
			sslContext.init(null, tm, new java.security.SecureRandom());
			// 从上述SSLContext对象中得到SSLSocketFactory对象
			SSLSocketFactory ssf = sslContext.getSocketFactory();

			URL url = new URL(requestUrl);
			HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
			conn.setSSLSocketFactory(ssf);

			Utils.setReqHeader(headers, conn);

			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setUseCaches(false);
			// 设置请求方式（GET/POST）
			conn.setRequestMethod(requestMethod);

			if ("GET".equalsIgnoreCase(requestMethod)) {
				conn.connect();
			}

			// 当有数据需要提交时
			if (null != outputStr) {
				OutputStream outputStream = conn.getOutputStream();
				// 注意编码格式，防止中文乱码
				outputStream.write(outputStr.getBytes("UTF-8"));
				outputStream.close();
			}

			// 将返回的输入流转换成字符串
			InputStream inputStream = conn.getInputStream();

			String content = IOUtils.toString(inputStream, "UTF-8");
			IOUtils.closeQuietly(inputStream);
			conn.disconnect();
			return RespDTO.builder().content(content).headers(conn.getHeaderFields()).code(conn.getResponseCode())
					.cookie(conn.getHeaderField(Constants.HEADER_SET_COOKIE)).build();

		} catch (Exception e) {
			e.printStackTrace();
			log.error("https request error:{}", e);
		}

		return RespDTO.builder().build();

	}

	public static void forward(HttpServletRequest req, HttpServletResponse resp, String body) throws IOException {

		IRespHandler respHandler = RespHandlerFactory.getInstance().create(req);

		respHandler.invoke(req, resp, body);
	}

	public static String proxy(HttpServletRequest req, HttpServletResponse resp) throws MalformedURLException {

		String content = null;

		String target = req.getParameter(Constants.TARGET_NAME);
		if (StringUtils.isEmpty(target)) {
			content = "请设置要代理访问的target页面，例如：?" + Constants.TARGET_NAME + "=http://www.pingan.com/licai.shtml";
		} else {
			URL url = new URL(target);

			int port = url.getPort();
			String portS = String.valueOf(port);
			if (port == 80 || port == 443 || port == -1) {
				portS = "";
			} else {
				portS = ":" + portS;
			}

			String baseUrl = url.getProtocol() + "://" + url.getHost() + portS + "/";

			// set cookies
			Utils.addCookie(resp, Constants.COOKIE_NAME_BASE_URL, baseUrl, 3600 * 24);

			RespDTO respDTO = ProxyUtil.request(Utils.getHeaders(req), target, "GET", null);

			// eg: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
			// BIGipServerTOA-prd-dmzweb_PrdPool=1157897388.24949.0000; path=/
			// System.out.println(respDTO.getCookie());
			String cookie = respDTO.getCookie();
			if (StringUtils.isNotEmpty(cookie)) {
				String[] arr = cookie.split(";");
				String[] arr2 = arr[0].trim().split("=");
				Utils.addCookie(resp, arr2[0], arr2[1], 3600 * 24);
			}

			content = Utils.inject(respDTO.getContent(), baseUrl, url.getPath());

			resp.setStatus(respDTO.getCode());
			Utils.setRespHeader(resp, respDTO.getHeaders());

		}

		return content;
	}

}